package com.oracle.outsidein;

import com.oracle.outsidein.pool.OitType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;

@Slf4j
public class OutsideinUtils {
    private static final String EXECUTABLE_DEFAULT = "sdk/demo/exsimple";
    private static final String EXECUTABLE_WINDOWS = "sdk/demo/exsimple.exe";

    private static class DefaultOfficeHomeHolder { // NOSONAR
        /* default */ static final File INSTANCE;

        static {
            if (SystemUtils.IS_OS_MAC) {
                throw new IllegalStateException("not support macos");
            } else if (StringUtils.isNotBlank(System.getProperty("outsidein.home"))) {
                INSTANCE = new File(System.getProperty("outsidein.home"));
            } else if (SystemUtils.IS_OS_WINDOWS) {
                final String programFiles64 = System.getenv("ProgramFiles");
                final String programFiles32 = System.getenv("ProgramFiles(x86)");
                INSTANCE = findOfficeHome(EXECUTABLE_WINDOWS, programFiles64 + File.separator + "outsidein", programFiles32 + File.separator + "outsidein");
            } else {
                INSTANCE = findOfficeHome(EXECUTABLE_DEFAULT, "/opt/outsidein", "/opt/outsidein");
            }
        }

        private static File findOfficeHome(final String executablePath, final String... homePaths) {
            return Stream.of(homePaths)
                    .map(File::new)
                    .filter(homeDir -> new File(homeDir, executablePath).isFile())
                    .findFirst()
                    .orElse(null);
        }
    }

    public static File getDefaultOfficeHome() {
        return DefaultOfficeHomeHolder.INSTANCE;
    }

    public static File getOfficeExecutable(final File outsideinHome, String tool) {
        if (SystemUtils.IS_OS_MAC) {
            throw new IllegalStateException("not support macos");
        }
        String dir = outsideinHome + "/" + tool;
        if (SystemUtils.IS_OS_WINDOWS) {
            return new File(dir, EXECUTABLE_WINDOWS);
        }
        return new File(dir, EXECUTABLE_DEFAULT);
    }

    public static Map<OitType, String> validateHome(final File outsideinHome, String tool) {
        if (outsideinHome == null) {
            throw new IllegalStateException("outsideinHome not set and could not be auto-detected");
        }
        if (!outsideinHome.isDirectory()) {
            throw new IllegalStateException("outsideinHome doesn't exist or is not a directory: " + outsideinHome);
        }
        Map<OitType, String> execMap = new HashMap<>();
        File file = getOfficeExecutable(outsideinHome, OitType.wv + tool);
        if (file.isFile()) {
            log.info("outsideinHome found {} {}",OitType.wv, file.getPath());
            execMap.put(OitType.wv, file.getPath());
        }
        file = getOfficeExecutable(outsideinHome, OitType.ix + tool);
        if (file.isFile()) {
            log.info("outsideinHome found {} {}",OitType.ix, file.getPath());
            execMap.put(OitType.ix, file.getPath());
        }
        file = getOfficeExecutable(outsideinHome, OitType.px + tool);
        if (file.isFile()) {
            log.info("outsideinHome found {} {}",OitType.px, file.getPath());
            execMap.put(OitType.px, file.getPath());
        }
        if (execMap.isEmpty()) {
            throw new IllegalStateException("Invalid outsideinHome: it doesn't contain exsimple: " + outsideinHome + "/XX" + tool);
        }
        return execMap;
    }

    public static void validateWorkingDirectory(final File workingDir) {
        if (!workingDir.isDirectory()) {
            throw new IllegalStateException("workingDir doesn't exist or is not a directory: " + workingDir);
        }
        if (!workingDir.canWrite()) {
            throw new IllegalStateException("workingDir '" + workingDir + "' cannot be written to");
        }
    }

    private OutsideinUtils() {
        throw new AssertionError("Utility class must not be instantiated");
    }
}
